#include    "app.h"
#include    "os.h"
#include    "scheduler.h"
#include    "socket.h"

#include    <csignal>
#include    <thread>
#include    <stdexcept>

#if !defined(_WIN32)
#	include		<sys/resource.h>
#	include		<unistd.h>
#endif

namespace {
    App * g_app = nullptr;

    void Quit(int sig) {
        if (g_app) g_app->Stop(sig);
    }
}

App::App() : _running(false), _exit_code(0), _frame_time(50) {
    if (!g_app) {
        g_app = this;
    } else {
        throw std::runtime_error("There is more than one application instance!");
    }
}

int App::Run(int argc, char * argv[]) {
    OS::SetCWD(OS::GetDirName(argv[0]));

#if !defined(_WIN32)
    struct rlimit set;
    set.rlim_cur = RLIM_INFINITY;
    set.rlim_max = RLIM_INFINITY;

    setrlimit(RLIMIT_CORE, &set);
    signal(SIGPIPE, SIG_IGN);
#endif

    signal(SIGINT, &Quit);
    signal(SIGTERM, &Quit);
    signal(SIGABRT, &Quit);

    if (!OnInit(argc, argv)) return 0;

    _running = true;
    double next = OS::Tick() + _frame_time;
    while (_running) {
        BreathAllSockets();
        GScheduler.Breath();
        OnBreath();

        double left = next - OS::Tick();
        if (left > 0) {
            std::this_thread::sleep_for(std::chrono::milliseconds((int)(left + 1)));
        } else {
            LOG_WARN("FRAME_DELAY: %.04lf ms", (-left));
        }

        next += _frame_time;
    }

    OnExit();
    return 0;
}

void App::Stop(int code) {
    _exit_code = code;
    _running = false;
}